import { Collider2D, Contact2DType, director, game, IPhysics2DContact, Vec2, Vec3 } from "cc";
import { Enemy } from "../../Role/Script/Enemy";
import { Role } from "../../Role/Script/Role";
import EventManager from "../../Script/Common/EventManager";
import GlobalData from "../../Script/Common/GlobalData";
import { EventType } from "../../Script/GameSpecial/GameEventType";
import { GlobalEnum } from "../../Script/GameSpecial/GlobalEnum";

/**AI管理器 */
export default class AIManager {
    //静态类
    private constructor() { }

    public static init() {
        this.allAi = {};
        this.onEvents();
    }
    protected static onEvents() {
        EventManager.on(EventType.LevelEvent.enemyAtkFinish, this.onEnemyAtkFinish, this);
        EventManager.on(EventType.LevelEvent.enemyHitSuccess, this.onEnemyHitSuccess, this);
        EventManager.on(EventType.LevelEvent.enemyJumpInPortal, this.onEnemyJumpInPortal, this);
        EventManager.on(EventType.LevelEvent.enemyJumpOutPortalFinish, this.onEnemyJumpOutPortalFinish, this);

    }
    public static reset() {
        for (let key in this.allAi) {
            AIPool.put(this.allAi[key]);
        }
        this.allAi = {};
    }

    /**************************************************管理对象**************************************************/
    protected static allAi: { [id: number]: AI } = {};

    public static addEnemy(enemy: Enemy) {
        let id = enemy.Id;
        this.allAi[id] = AIPool.get(enemy);
    }
    public static removeEnemy(enemy: Enemy) {
        let ai = this.allAi[enemy.Id];
        if (!!ai) {
            AIPool.put(ai);
            delete this.allAi[enemy.Id];
        }
    }
    public static enterLevel() {
        for (let key in this.allAi) {
            this.allAi[key].enterLevel();
        }
    }

    public static customUpdate(dt: number) {
        for (let key in this.allAi) {
            this.allAi[key].customUpdate(dt);
        }
    }

    /**************************************************事件回调**************************************************/
    protected static onEnemyAtkFinish(enemy: Enemy) {
        if (!!this.allAi[enemy.Id]) {
            this.allAi[enemy.Id].onAtkEnd();
        }
    }
    protected static onEnemyHitSuccess(enemy: Enemy) {
        if (!!this.allAi[enemy.Id]) {
            this.allAi[enemy.Id].onHitSuccess();
        }
    }
    protected static onEnemyJumpInPortal(enemy: Enemy) {
        if (!!this.allAi[enemy.Id]) {
            this.allAi[enemy.Id].onJumpInPortal();
        }
    }
    protected static onEnemyJumpOutPortalFinish(enemy: Enemy) {
        if (!!this.allAi[enemy.Id]) {
            this.allAi[enemy.Id].onJumpOutPortalFinish();
        }
    }

}

/**AI对象池 */
class AIPool {
    protected static pool: AI[] = [];
    public static get(role: Role) {
        if (this.pool.length > 0) {
            let ai = this.pool.pop();
            ai.reuse(role);
            return ai;
        }
        let ai = new AI();
        ai.init(role);
        return ai;
    }
    public static put(ai: AI) {
        ai.unuse();
        this.pool.push(ai);
    }
}

/**AI基类 */
class AI {

    /**************************************************通用流程**************************************************/
    public init(role) {
        this.initCustomUpdateState();
        this.setRole(role);
        this.registAllCustomUpdate();
    }
    protected registAllCustomUpdate() {
        this.registCustomUpdate(state.atking, this.stepAtking);
        this.registCustomUpdate(state.moveFree, this.stepMoveFree);
        this.registCustomUpdate(state.moveToAtk, this.stepMoveToAtk);
        this.registCustomUpdate(state.runAway, this.stepRunAway);
    }

    public reset() {
        this.role = null;
        this.player = null;
        this.resetCustomUpdateState();
    }
    public unuse() {
        this.offColliderEvents();
        this.reset();
    }
    public reuse(role) {
        this.setRole(role);
    }

    public enterLevel() {
        this.onColliderEvents();
        let player = GlobalData.get(GlobalEnum.myGlobalDataType.player);
        this.player = player;
        let r = this.role.faceRadian;
        this.moveRadian(r);
        this.enterCustomUpdateState(state.moveFree);
        this.lastAtkTime = director.getCurrentTime();
    }

    /**************************************************管理对象**************************************************/

    protected player: Role = null;
    protected role: Role = null;
    public setRole(role: Role) {
        this.role = role;
    }


    /**************************************************碰撞回调**************************************************/
    //注册碰撞回调
    protected onColliderEvents() {
        if (!!this.role) {
            this.role.onCollCb(this.onConcatBegin, this);
        }
    }
    protected offColliderEvents() {
        if (!!this.role) {
            this.role.offCollCb(this.onConcatBegin, this);
        }
    }
    protected onConcatBegin(self: Collider2D, other: Collider2D, concat: IPhysics2DContact) {
        switch (other.group) {
            case GlobalEnum.RigidGroup.default: {
                this.onCollBarrier();
                break;
            }
            case GlobalEnum.RigidGroup.enmey: {
                //砍人
                this.onCollRole();
                break;
            }
            case GlobalEnum.RigidGroup.ground: {
                //碰到不可破坏的障碍，转向
                this.onCollGround();
                break;
            }
            case GlobalEnum.RigidGroup.player: {
                if (!!this.player && this.player.isAlive) {
                    this.onCollRole();
                } else {
                    // this.onCollGround();
                    this.moveRadian(this.role.faceRadian + 3.14);
                }
                break;
            }
        }
    }
    protected onCollBarrier() {
        if (Math.random() < 0.7 && director.getCurrentTime() - this.lastAtkTime > 4000) {
            this.startAtk();
        } else if (director.getCurrentTime() - this.collGroundTime > 1000) {
            this.moveRadian(Math.random() * 6.28);
        }
    }
    protected collGroundTime: number = 0;
    protected onCollGround() {
        let t = director.getCurrentTime();
        if (t - this.collGroundTime > 1000) {
            this.moveRadian(Math.random() * 6.28);
        }
    }
    protected onCollRole() {
        // if (director.getCurrentTime() - this.lastAtkTime > 1000) {
        this.startAtk();
        // }
    }

    /**************************************************运行模式**************************************************/
    //#region 自定义的主循环功能
    /**自定义的运行状态 */
    protected _customUpdateState: any;
    public get customUpdateState() { return this._customUpdateState; }
    /**运行状态与运行函数的映射表，key：运行状态枚举值，value：运行函数 */
    protected customUpdateMap;
    /**当前状态对应的每帧更新函数 */
    protected customStep: (dt: number) => void;
    protected stepEmpty(dt: number) { }
    /**初始化运行状态 */
    protected initCustomUpdateState() {
        this._customUpdateState = null;
        this.customStep = this.stepEmpty;
        this.customUpdateMap = {};
    }
    /**重置运行状态 */
    protected resetCustomUpdateState() {
        this._customUpdateState = null;
        this.customStep = this.stepEmpty;
    }
    /**注册运行状态与函数，注册后，脚本切换到该状态时，自定义更新函数中将执行该方法 */
    protected registCustomUpdate(state: any, step: Function) {
        if (!this.customUpdateMap) {
            this.customUpdateMap = {};
        }
        this.customUpdateMap[state] = step;
    }
    /**切换到指定的运行状态 */
    protected enterCustomUpdateState(state: any) {
        if (this._customUpdateState != state) {
            this._customUpdateState = state;
            if (!!this.customUpdateMap[state]) {
                this.customStep = this.customUpdateMap[state];
            } else {
                this.customStep = this.stepEmpty;
            }
        }
    }
    /**自定义的每帧更新函数 */
    public customUpdate(dt: number) {
        this.customStep && this.customStep(dt);
    }
    //#endregion

    //运行模式
    protected stepAtking(dt: number) {

    }
    //自由行走
    protected cachePos: Vec2 = new Vec2();
    protected moveElapsed: number = 0;
    /**最后一次攻击的时间戳 */
    protected lastAtkTime: number = 0;
    protected stepMoveFree(dt: number) {
        this.moveElapsed += dt;
        if (this.moveElapsed > 2) {
            this.moveElapsed = 0;
            this.moveRadian(Math.random() * 6.28);
        } else if (director.getCurrentTime() - this.lastAtkTime > 5000) {
            if (!this.checkAtkPlayer()) {
                this.checkAtkEnemy();
            }
        }
    }
    protected checkAtkPlayer(): boolean {
        if (!this.player || !this.player.isAlive) {
            return false;
        }
        let r = this.role.atkRadiusSqr * 0.25;
        // let r = this.role.atkRadius - 2;
        // r *= r;
        let e = this.player.node.position;
        if (this.checkInAtkScope(e, r)) {
            this.startAtk();
            return true;
        } else {
            return false;
        }
    }
    protected checkAtkEnemy(): boolean {
        //有敌人进入攻击范围时立刻攻击
        let r = this.role.atkRadiusSqr + 1;
        let enemies = GlobalData.get(GlobalEnum.myGlobalDataType.enemies);
        for (let i = enemies.length - 1; i >= 0; --i) {
            if (enemies[i].Id == this.role.Id) continue;
            let e = enemies[i].node.position;
            if (this.checkInAtkScope(e, r)) {
                this.startAtk();
                return true;
            }
        }
        return false;
    }
    protected checkInAtkScope(e: Vec3, r: number) {
        let p = this.role.node.position;
        let v = this.cachePos;
        v.x = e.x - p.x;
        v.y = p.z - e.z;
        if (v.x * v.x + v.y * v.y > r) {
            return false;
        }
        let s = this.role.speed;
        return v.x * s.x - v.y * s.z > 0;
    }
    //追击
    protected stepMoveToAtk(dt: number) {

    }
    //逃跑
    protected stepRunAway(dt: number) {

    }
    protected stepPortal(dt: number) {

    }

    /**************************************************角色动作**************************************************/
    protected startAtk() {
        this.lastAtkTime = director.getCurrentTime();
        this.role.startAtk();
        this.enterCustomUpdateState(state.atking);
    }
    protected moveDir(x: number, z: number) {
        this.role.setMoveDir(x, z);
    }
    protected moveRadian(radian: number) {
        this.role.setMoveRadian(radian);
        this.collGroundTime = director.getCurrentTime();
    }

    /**************************************************事件回调**************************************************/

    public onStartAtk() {

    }
    public onAtkEnd() {
        //继续行走
        let r = Math.random() * 6.28;
        this.moveRadian(r);
        this.moveElapsed = 0;
        this.enterCustomUpdateState(state.moveFree);
    }
    public onBeHit() {

    }
    public onHitSuccess() {

    }
    public onJumpInPortal() {
        this.enterCustomUpdateState(state.portal);
    }
    public onJumpOutPortalFinish() {
        let r = this.role.faceRadian;
        this.moveRadian(r);
        this.moveElapsed = 0;
        this.enterCustomUpdateState(state.moveFree);
    }
}

enum state {
    /**正在攻击 */
    atking,
    /**自由行走 */
    moveFree,
    /**逃跑 */
    runAway,
    /**追击 */
    moveToAtk,
    /**传送中 */
    portal,
}